// hallmachine.h
#pragma once

#include "common.h"
#include "CSerialPort/SerialPortInfo.h"
#include "CSerialPort/SerialPort.h"
#include "../import/Src/alglib-3.18.0.cpp.gpl/alglib-cpp/src/interpolation.h"
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#include <experimental/filesystem>


#define DEFAULT_STR ""

#define X_MAX_MM 300
#define Y_MAX_MM 300
#define Z_MAX_MM 5000

namespace hallmachine {
	using namespace common;

	/// <summary>
	/// UMAC下位机发来的数据包
	/// </summary>
	typedef struct DLL_HALLMACHINE_API _UMACData {


		bool laser_status;
		bool zz1_tongbu;
		bool force_fast_stop = false;
		bool pressure;
		bool vacuum;
		bool manual;
		bool z_stoped, x_stoped, y_stoped, z2_stoped, a_stoped, c_stoped;


		double z_pos_mm, x_pos_mm, y_pos_mm, a_ang_deg, z2_pos_mm/*激光尺*/, c_ang_deg;

		double z_speed, x_speed, y_speed;
		// 正负限位
		bool z_limit_pos_plus, z_limit_pos_minus;
		bool x_limit_pos_plus, x_limit_pos_minus;
		bool y_limit_pos_plus, y_limit_pos_minus;
		bool a_limit_pos_plus, a_limit_pos_minus;
		bool  c_limit_pos_plus, c_limit_pos_minus;



		_UMACData() :z_pos_mm(0), x_pos_mm(0), y_pos_mm(0),
			a_ang_deg(0), z2_pos_mm(0)/*激光尺*/, c_ang_deg(0),
			z_speed(0), x_speed(0), y_speed(0),
			z_limit_pos_plus(0), z_limit_pos_minus(0),
			x_limit_pos_plus(0), x_limit_pos_minus(0),
			y_limit_pos_plus(0), y_limit_pos_minus(0),
			a_limit_pos_plus(0), a_limit_pos_minus(0) {}
	} UMACData, * PUMACData;


	class DLL_HALLMACHINE_API HallMachine {
	public:
		HallMachine(/*const std::string& default_config_path = DEFAULT_STR*/);
		~HallMachine();
		bool send_cmd(std::string cmd);

		/// <summary>
		/// 连接并初始化下位机、GPIB设备和COM串口设备
		/// </summary>
		/// <returns></returns>
		bool open();
		bool close();

		/// <summary>
		/// 读取一次UMAC的数据
		/// </summary>
		/// <returns>true if all is OK</returns>
		bool update_UMAC();
		/// <summary>
		/// 从GPIB口读取一次数据（不涉及更进一步的处理）
		/// </summary>
		/// <returns>true if all is OK</returns>
		bool update_GPIB();
		//bool update_all();

		/// <summary>
		/// 设置激光参考点
		/// </summary>
		/// <returns></returns>
		bool set_laser_ref_pt();

		/// <summary>
		/// 毫米转化为光栅尺最小单位cts
		/// </summary>
		/// <param name="mm">毫米</param>
		/// <returns>光栅尺</returns>
		static inline int64_t mm_to_cts(double mm) {
			return static_cast<double>(1e4 * mm);
		};

		/// <summary>
		/// 光栅尺最小单位cts转化为毫米
		/// </summary>
		/// <param name="cts">光栅尺</param>
		/// <returns>毫米</returns>
		static inline double cts_to_mm(int64_t cts) { return cts * 1e-4; };


		/// <summary>
			/// 移动指定距离
			/// </summary>
			/// <param name="distance_mm">指定的移动距离，若为负，则反向移动</param>
			/// <returns></returns>
		bool x_jog(double distance_mm);

		/// <summary>
		/// 移动到指定位置
		/// </summary>
		/// <param name="target_pos_mm"></param>
		/// <returns></returns>
		bool x_jog_to(double target_pos_mm);

		bool y_jog(double distance_mm);
		bool y_jog_to(double target_pos_mm);
		bool z_jog(double distance_mm);
		bool z_jog_to(double target_pos_mm);


		/// <summary>
		/// 轴位置重回出厂设置的零点（参考点）
		/// </summary>
		/// <returns></returns>
		bool x_find_zero();
		bool y_find_zero();
		bool z_find_zero();

		bool x_stop();
		bool y_stop();
		bool z_stop();

		/// <summary>
		/// 设置手轮控制模式
		/// </summary>
		/// <returns></returns>
		bool set_manual(bool manual);

		/// <summary>
	  /// 设置z轴移动速度
	  /// </summary>
	  /// <param name="speed">常用值有100, 200, 300, 400, 500</param>
	  /// <returns></returns>
		bool set_z_speed(int speed);

		bool set_x_speed(int speed);
		bool set_y_speed(int speed);
		bool set_a_speed(int speed);
		bool set_c_speed(int speed);
	public:
		bool initialized_;
		std::shared_ptr<itas109::CSerialPort> sp;  // 用于与电源COM口通信
		UMACData umac_data_;
		Vec3d V_;        // unit in V
		double current_A_;   // 当前励磁电流，unit in A
	private:

		std::experimental::filesystem::
			path config_path;

		Vec3<alglib::spline1dinterpolant> spline_V_to_B_;
		ViSession defaultRM_;
		ViSession vi_x_;
		ViSession vi_y_;
		ViSession vi_z_;
		ViUInt32 actual_x_, actual_y_, actual_z_;
	};

	DLL_HALLMACHINE_API HallMachine getInstance();
	DLL_HALLMACHINE_API std::ostream& operator<<(std::ostream& os,
		const UMACData& data);

}; // namespace hallmachine

EXTERN_C{
	// DLL_HALLMACHINE_API bool  open();
	DLL_HALLMACHINE_API void test();
}

inline void test_new() { test(); }